Hirdetés

Alkalmazásfejlesztés badára: Fény és anyagok az OpenGL-ben

Let there be light!

Ha megfigyeltétek a blog keretein belül eddig elkészített objektumokat, mindegyik egyszínű volt. Ez azért van, mert nem használtunk semmilyen fényforrást és anyagot, ezért az OpenGL a háromszögek összes pontját ugyanolyan színűre festette, mint amit megadtunk a glCoror4f-fel. Ennek kiküszöböléséhez muszáj a fényforrásokhoz nyúlnunk, egy megfelelően összerakott megvilágítás nagyon fel tudja dobni a jelenetet. A használatuk nagyon egyszerű, egyszerűen engedélyezni kell az inicializáló függvényben a glEnable(GL_LIGHTING) paranccsal. Azonban ha most renderelünk egyet, furcsa módon azt tapasztaljuk, hogy nem világosság, hanem sötétség támadt a kijelzőnkön: minden objektum matt fekete. Ez azért van, mert nem definiáltunk saját fényforrást, ne is vesztegessük az időt, tegyük meg.

Az OpenGL-ben maximum 8 fényforrást használhatunk egy jelenetben, ezekre az előre definiált GL_LIGHT0 - 7-tel hivatkozhatunk. Egy fényforráshoz öt tulajdonságot kell hozzárendelni, a tulajdonságokat a glLight függvény segítségével rendelhetjük hozzájuk. Az egyik a pozíció, ezt szokás szerint egy háromdimenziós vektorral adhatjuk meg. A másik a fényforrás típusa típusa, ez lehet spot, azaz irányfényforrás, ami egy elemláprára hasonlít, azaz csak egy irányba világít, ekkor meg kell adni a világítás irányvektorát is. A másik típus a pontszerű fényforrás, ez egy adott pozícióból a szélrózsa minden irányába küldi a sugarakat. Ez után beállíthatjuk a lecsengést is (attenuation), ami azt adja meg, hogy a fénysugár milyen gyorsan veszít az erejéből A következő lépés a fény színének meghatározása. Ez kicsit fura az OpenGL-ben, a fényt három komponensre bontja: diffúz, ambiens és csúcsfény. A diffúz (GL_DIFFUSE) nagyjából a szórt fénynek felel meg, ami nem direktben mutat az objektumunkra, azaz egy olyan sugárnak, ami “pattant” már egyet egy tárgyon, átvilágít a függönyön, stb. Az ambiens az a komponens, ami minden ponthoz hozzáadódik, függetlenül attól, hogy éri-e fény vagy nem. Tehát ha túl sötétek az objektumaink, az ambiens fény értékét érdemes növelni. A harmadik a csúcsfény (specular), ez annak a komponensnek az ereje, ahol a fény direktben eltalálja a testeinket, azaz a normálvektorok a fényforrás felé mutatnak. Apropó normálvektorok: ahhoz, hogy a fényforrásaink hatása megmutatkozzon az objektumainkat, ezeket be kell állítanunk az egyes háromszögeknél. A normálvektor az a vektor, amely merőleges a háromszögre. A fény ereje egy adott pontban attól függ, hogy a beérkező fénysugár milyen szöget zár be a normálvektorunkkal. Minél kisebb a szög, annál erősebb lesz a fény kontribúciója a pixel színéhez. A normálvektorokat sajnos kézzel kell beállítanunk, viszont létezik egy matematikai egyenletrendszer, ami egy háromszög három pontjából kicsapja nekünk a normálvektort (lásd alább). Megkülönböztetünk háromszög- és vertex-alapú normálvektorokat, ám ahhoz, hogy ezek szerepét bemutassam, át kell ugranunk az árnyalás területére.

Árnyalási modellek

Az OpenGL-ben kétfajta árnyalási modellt különböztetünk meg: GL_FLAT és GL_SMOOTH, ezeket az init részben, a glShadeModel függvény paraméterébe töltve aktiválhatjuk, egyszerre természetesen csak egyet. Az első lényege, hogy az árnyalást az egész háromszögre számolja ki, minden pixel ugyanolyan színű lesz. Ez elég csúnya és életszerűtlen képet eredményez, csak akkor érdemes használni, ha valaki a retro hatásra megy. Ami számunkra érdekes, az a smooth árnyalási modell, ez az úgynevezett Goraud-árnyalást használja. Ez még mindig gyengébb eredményt ad, mint az összetettebb társai, például a Phong árnyalás, azonban cserébe sokkal kevésbé számítás-igényes, és OpenGL alatt ez a legjobb. A Goraud algoritmus lényege abban rejlik, hogy itt nem a hármoszögre, hanem az azt alkotó vertexekre definiáljuk a normálvektorokat. A felületeink háromszögekből állnak, a vertexeknél összeadódnak az egyes normálvektorok, majd ezekre a Phong reflection model alapján számolja ki az árnyalási szintet, ergo meghatározza a színt. A három vertex így kapott színei pedig arányosan kitöltik a háromszöget. Nagy hibája, hogy ha egy fényforrás úgy világít meg egy háromszöget, hgoy a csúcsfény nem ér el az egyik vertexben sem, a Goraud-árnyalási modell miatt egyáltalán nem fog látszódni a specular. De hát ez van, ezt kell szeretni. Szóval, beállítottuk az árnyalási modellt, az előzőleg kiszámított normalokat is beraktuk egy tömbbe és megetettük a glNormalPointer-rel, rendereljünk hát egyet! A kapott képen már látszik az árnyalás, azonban minden objektumunk egyszínű szürkében pompázik. Ahhoz, hogy a modellünk lekezelje a három fénykomponenst, egy megfelelő anyagot kell társítanunk hozzá.

Anyagok

Smooth árnyalás és fények esetén muszáj valamilyen materialt is definiálnunk, hogy a várt eredményre jussunk. Ha használunk valamiylen color array-t, a glEnable(GL_COLOR_MATERIAL) bit bebillentésével az OpenGL kigenerál nekünk egy anyagot, azonban ez messze elmarad a tökéletestől, definiáljuk hát a sajátunkat. Ez lesarkítva három háromtagú glFloat tömböt jelent, minden tömb az egyik fénykomponensre reagál: meg kell adnunk egy ambiens, diffúz és spekuláris színt. Ezeket a glMaterialfv függvénnyel kell megetetnünk. A függvény első paramétere, hogy a háromszög melyik oldalára rakja (GL_FRONT: csak a kamerával szembenire, GL_FRONT_AND_BACK: mindkét oldalra, utóbbit érdemes választani), melyik fénykomponensnek felel meg a tömbünk, és végül egy referencia a tömbre. A materialt úgyanúgy használjuk, mintha a glColor4f-et használnák.

Ezzel végére is értünk a mai bejegyzésnek, a felhasznált kód természetesen ismét letölthető innen.

holdmester

Azóta történt

Előzmények